﻿#define _CRT_SECURE_NO_WARNINGS 1
//******************************操作符*****************************//

//左移操作符:左边抛弃、右边补0
//#include <stdio.h>
//int main()
//{
//	int num = 10;
//	int n = num << 1;
//	printf("n= %d\n", n);//20
//	printf("num= %d\n", num);
//	return 0;
//}


//右移操作符:1. 逻辑右移：左边用0填充，右边丢弃
//		    2. 算术右移：左边用原该值的符号位填充，右边丢弃
//#include <stdio.h>
//int main()
//{
//	int num = 10;
//	int n = num >> 1;
//	printf("n= %d\n", n);//5
//	printf("num= %d\n", num);
//	return 0;
//}


//警告：对于移位运算符，不要移动负数位，这个是标准未定义的。
//int main()
//{
//	int num = 10;
//	num >> -1;//error
//	return 0;
//}


//位操作符：&、|、^、~，他们的操作数必须是整数。
//#include <stdio.h>
//int main()
//{
//	int num1 = -3;
//	int num2 = 5;
//	printf("%d\n", num1 & num2);
//	printf("%d\n", num1 | num2);
//	printf("%d\n", num1 ^ num2);
//	printf("%d\n", ~0);
//	return 0;
//}


//面试题：不能创建临时变量（第三个变量），实现两个整数的交换。
//#include <stdio.h>
//int main()
//{
//	int a = 10;
//	int b = 20;
//	a = a ^ b;
//	b = a ^ b;
//	a = a ^ b;
//	printf("a = %d b = %d\n", a, b);
//	return 0;
//}


//练习1：编写代码实现：求⼀个整数存储在内存中的⼆进制中1的个数。
//⽅法1
//#include <stdio.h>
//int main()
//{
//	int num = 10;
//	int count = 0;//计数
//	while (num)
//	{
//		if (num % 2 == 1)
//			count++;
//		num = num / 2;
//	}
//	printf("二进制中1的个数 = %d\n", count);
//	return 0;
//}
//思考这样的实现⽅式有没有问题？
//⽅法2：
//#include <stdio.h>
//int main()
//{
//	int num = -1;
//	int i = 0;
//	int count = 0;//计数
//	for (i = 0; i < 32; i++)
//	{
//		if (num & (1 << i))
//			count++;
//	}
//	printf("二进制中1的个数 = %d\n", count);
//	return 0;
//}
////思考还能不能更加优化，这⾥必须循环32次的。
////⽅法3：
//#include <stdio.h>
//int main()
//{
//	int num = -1;
//	int i = 0;
//	int count = 0;//计数
//	while (num)
//	{
//		count++;
//		num = num & (num - 1);
//	}
//	printf("二进制中1的个数 = %d\n", count);
//	return 0;
//}
//这种⽅式是不是很好？达到了优化的效果，但是难以想到。


//练习2：⼆进制位置0或者置1
//编写代码将13⼆进制序列的第5位修改为1，然后再改回0
//#include <stdio.h>
//int main()
//{
//	int a = 13;
//	a = a | (1 << 4);
//	printf("a = %d\n", a);
//	a = a & ~(1 << 4);
//	printf("a = %d\n", a);
//	return 0;
//}


//逗号表达式，就是⽤逗号隔开的多个表达式。
//逗号表达式，从左向右依次执⾏。整个表达式的结果是最后⼀个表达式的结果。
//代码1
//int a = 1;
//int b = 2;
//int c = (a > b, a = b + 10, a, b = a + 1);//逗号表达式
////c是多少？
////代码2
//if (a = b + 1, c = a / 2, d > 0)
////代码3
//a = get_val();
//count_val(a);
//while (a > 0)
//{
//	//业务处理
//	//...
//	a = get_val();
//	count_val(a);
//}
//如果使⽤逗号表达式，改写：
//while (a = get_val(), count_val(a), a > 0)
//{
//	//业务处理
//}


//[ ] 下标引用操作符
//操作数：⼀个数组名 + ⼀个索引值(下标)
//int arr[10];//创建数组
//arr[9] = 10;//实⽤下标引⽤操作符。
////[] 的两个操作数是arr和9。


//函数调⽤操作符
//接受⼀个或者多个操作数：第⼀个操作数是函数名，剩余的操作数就是传递给函数的参数。
//#include <stdio.h>
//void test1()
//{
//	printf("hehe\n");
//}
//void test2(const char* str)
//{
//	printf("%s\n", str);
//}
//int main()
//{
//	test1(); //这⾥的()就是作为函数调⽤操作符。
//	test2("hello bit.");//这⾥的()就是函数调⽤操作符。
//	return 0;
//}


//结构是⼀些值的集合，这些值称为成员变量。结构的每个成员可以是不同类型的变量，如：
//标量、数组、指针，甚⾄是其他结构体。
//结构的声明
//struct tag
//{
//	member - list;
//}variable - list;

//struct Stu
//{
//	char name[20];//名字
//	int age;//年龄
//	char sex[5];//性别
//	char id[20];//学号
//}; //分号不能丢

//结构体变量的定义和初始化
////代码1：变量的定义
//struct Point	//名为Point的结构体类型
//{
//	int x;
//	int y;
//}p1; //声明类型的同时定义变量p1
//struct Point p2; //定义结构体变量p2
////代码2:初始化。
//struct Point p3 = { 10, 20 };
//struct Stu //类型声明
//{
//	char name[15];//名字
//	int age; //年龄
//};
//struct Stu s1 = { "zhangsan", 20 };//初始化
//struct Stu s2 = { .age = 20, .name = "lisi" };//指定顺序初始化
////代码3
//struct Node
//{
//	int data;
//	struct Point p;
//	struct Node* next;
//}n1 = { 10, {4,5}, NULL }; //结构体嵌套初始化
//struct Node n2 = { 20, {5, 6}, NULL };//结构体嵌套初始化


//结构成员访问操作符
//结构体成员的直接访问
//结构体成员的直接访问是通过点操作符（.）访问的。点操作符接受两个操作数。
// 使用方式：结构体变量.成员名
//#include <stdio.h>
//struct Point
//{
//	int x;
//	int y;
//}p = { 1,2 };
//int main()
//{
//	printf("x: %d y: %d\n", p.x, p.y);
//	return 0;
//}

//结构体成员的间接访问
//使用方式：结构体指针->成员名
//#include <stdio.h>
//struct Point
//{
//	int x;
//	int y;
//};
//int main()
//{
//	struct Point p = { 10, 20 };
//	struct Point* p1 = &p;
//	p1->x = 20;
//	p1->y = 30;
//	printf("x=%d, y=%d\n", p1->x, p1->y);
//	return 0;
//}

//#include <stdio.h>
//#include <string.h>
//struct Stu
//{
//	char name[15];//名字
//	int age; //年龄
//};
//void print_stu(struct Stu s)
//{
//	printf("%s %d\n", s.name, s.age);
//}
//void set_stu(struct Stu* ps)
//{
//	strcpy(ps->name, "李四");
//	ps->age = 28;
//}
//int main()
//{
//	struct Stu s = { "张三", 20 };
//	print_stu(s);
//	set_stu(&s);
//	print_stu(s);
//	return 0;
//}


//整型提升
//C语⾔中整型算术运算总是⾄少以缺省（默认）整型类型的精度来进⾏的。
//为了获得这个精度，表达式中的字符和短整型操作数在使⽤之前被转换为普通整型，这种转换称为整
//型提升。
//1. 有符号整数提升是按照变量的数据类型的符号位来提升的
//2. 无符号整数提升，高位补0
// 
////负数的整形提升
//char c1 = -1;
////变量c1的⼆进制位(补码)中只有8个⽐特位：
////1111111
////因为 char 为有符号的 char
////所以整形提升的时候，⾼位补充符号位，即为1
////提升之后的结果是：
////11111111111111111111111111111111
////正数的整形提升
//char c2 = 1;
////变量c2的⼆进制位(补码)中只有8个⽐特位：
////00000001
////因为 char 为有符号的 char
////所以整形提升的时候，⾼位补充符号位，即为0
////提升之后的结果是：
////00000000000000000000000000000001
////⽆符号整形提升，⾼位补0
//unsigned char c3 = -1;
////-1的补码为：1111 1111
////无符号char，整型提升，高位补0，得到：0000 0000 0000 0000 0000 0000 1111 1111


